home *** CD-ROM | disk | FTP | other *** search
- ;************************
- PAGE 55,132 ;Format .LST listing at 55 lines by 132 columns.
- TITLE TSRBONES Version 0.1 Jan 20 91 Robert Curtis Davis
- SUBTTL Introduction
- ;**************************************************************************
- ;
- ; TSRBONES.ASM Version 0.1 Jan 20 91
- ; A part of the TBONES software package.
- ;
- ; Copyright (C) 1990, 1991 by Robert Curtis Davis,
- ; All Rights Reserved.
- ;
- ; DESCRIPTION:
- ; ASM Program template for Terminate-and-Stay-Resident (TSR) programs
- ; that are activated by a specified HotKey WHEN DOS IS NOT
- ; BUSY (the InDOS Flag AND the DOS Critical Error Flag are zero)
- ; flag), OR WHEN DOS IS AT "BUSY IDLE" (when INT28h is called),
- ; AND WHEN NO HARDWARE INTERRUPT IRQ0-IRQ7 IS BEING HANDLED.
- ; This avoids problems of interfering with hardware interrupt
- ; handling and with DOS non-reentrancy; and allows DOS function
- ; calls above 0Ch to be used in the TSR routine. The TSR's code
- ; prevents multiple installations. Also checks DOS version and
- ; requires DOS Version 2 or later before installation is
- ; permitted.
- ;
- ; PURPOSE:
- ; Provides a skeletal framework program as a starting point in the
- ; design of your own HotKey TSRs which use DOS function calls, and
- ; for which a single installation is desired.
- ;
- ; E-mail address:
- ; Internet: sonny@trantor.harris-atd.com
- ;
- ; US Mail address:
- ; 430 Bahama Drive
- ; Indialantic, FL 32903
- ;
- ;**************************************************************************
- ;
- ; Special thanks to Roy Silvernail, whose persistent hacking (in the best
- ; sense of that word) and E-mail exchanges over the holiday season in
- ; December 1990, rooted out TBONES incompatibilities with Borland's TASM v.1.0.
- ;
- ;**************************************************************************
- ;
- ; Special thanks to Anto Prijosoesilo and Richard Brittain for E-mail
- ; exchanges which helped solve detailed problems with the implementation of
- ; the "Pseudo-Environment" idea.
- ;
- ;**************************************************************************
- ;
- ; Special thanks to David Kirschbaum, whose Toad Hall Tweaks significantly
- ; improved an early version of the TBONES Assembly Language code:
- ;
- ;v0.01 Toad Hall Tweak, 25 Nov 90
- ;**************************************************************************
- SUBTTL Code Segment
- PAGE
- ;**************************************************************************
- ;
- CodeSeg segment
- assume cs:CodeSeg,ds:CodeSeg
- BeginDump EQU $ ;Roy Silvernail - Keep TASM 1.0 happy
- ;when computing # resident paragraphs.
- ;
- org 2CH ;v0.01 ORG in PSP to pick up the
- envseg label word ;v0.01 Environment Segment.
- ;
- org 100h ;ORG for all COM programs.
- ;
- Entry PROC NEAR ;v0.01
- jmp TSRinit ;Jump over resident portion and
- ;initialize things and make code
- ;between Entry: and TSRinit: resident.
- ;
- ; Old Interrupt Vectors are stored here during TSR initialization:
- oldint09 dd ? ;Keyboard Hardware Interrupt.
- oldint13 dd ? ;Disk BIOS Interrupt.
- oldint16 dd ? ;Keyboard BIOS Interrupt.
- oldint28 dd ? ;DOS Idle Interrupt.
- ;
- ; For this HotKey TSR Template, specify Keyboard Interrupt 09h as the Hook:
- HOOK09 equ 09h ;Hooked Interrupt 09h.
- ; Int 13h is used to set a flag to prevent TSR trigger while disk active:
- HOOK13 equ 13h ;Hooked Interrupt 13h.
- ; Int 16h is hooked solely to provide way to check for prior TSR installation.
- HOOK16 equ 16h ;Hooked Interrupt 16h.
- ; We also have to hook Interrupt 28h to check for "DOS idle":
- HOOK28 equ 28h ;Hooked Interrupt 28h.
- ;
- bellgate db 0 ;Gate closed (=1) when in Bell routine.
- ;Gate open (=0) when not in Bell routine.
- ; Below:
- ; EQUates related to the Intel 8259A Programmable Interrupt Controller (PIC)
- ; chip. Hardware Interrupts IRQ0 through IRQ7 are controlled by the PIC.
- ;
- ; To really understand the nitty-gritty details of this stuff,
- ; you have to study the Intel Specification data for the 8259A PIC chip.
- ; These EQUates are used in this TSR to examine the PIC chip's In Service
- ; Register (ISR) to be sure that the TSR is not interrupting one of
- ; the hardware interrupt service routines. The reason for not wanting to
- ; interrupt these hardware interrupt service routines is that they are
- ; often time-critical and can be compromised by intruding on them with
- ; our TSR (for example, a hardware COM port interrupt-driven comm
- ; program might lose bytes on a modem transfer if we bull our way in and
- ; steal the CPU away from the comm program's service routine):
- PICPORT EQU 20h ;I/O Port for the 8259A PIC chip.
- ISRREQ EQU 00001011B ;This is a byte defining the
- ;Operation Control Word 3 (OCW3) to
- ;output on port 20h to make the PIC
- ;chip's In Service Register available
- ;for reading by the CPU on the
- ;next IN 20h command.
- ;
- ; EQUs defining Key Flag weights in the Key Flag Byte:
- RSHIFT equ 00000001B ;Right Shift Key Flag weight.
- LSHIFT equ 00000010B ;Left Shift Key Flag weight.
- CTRL equ 00000100B ;Ctrl Key Flag weight.
- ALT equ 00001000B ;Alt Key Flag weight.
- ;SCROLL equ 00010000B ;Scroll Lock Key Flag weight.
- ;NUM equ 00100000B ;Num Lock Key Flag weight.
- ;CAPS equ 01000000B ;Caps Lock Key Flag weight.
- INSRT equ 10000000B ;Ins Key Flag weight.
- ;
- LockKeyMask equ 10001111B ;For masking out Scroll, Caps,
- ;and Num Lock bits in KeyFlags.
- ;
- ; Pointer to "DOS busy" (InDOS) flag (loaded during TSR initialization):
- indosptr dd ?
- ;
- ; Pointer to "Critical Error" (CritErr) flag (loaded at TSR initialization):
- criterrptr dd ?
- ;
- ; Pointer to "Print Screen" busy (PrtScrn) flag
- prtscrn dd 00500000h
- ;
- ; hotkeyflag used to signal HotKey pressed to "DOS idle" Interrupt 28h:
- hotkeyflag db 0 ;hotkeyflag initially zero.
- ;
- ; diskflag used to prevent TSR trigger during time-critical Disk operations:
- diskflag db 0 ;diskflag initially zero.
- ;*************************************************************************
- ; Your HotKey is specified here:
- ; (This sample HotKey is set for Ctrl-Alt-B)
- ;
- ; Specify TSR's HotKey Shift Keys:
- KEYFLAGBYTE equ CTRL+ALT ;HotKey Flags
- ;
- ; Specify TSR's HotKey Scan Code:
- HOTKEY equ 30h ;'B' (for Bones) key
- ;
- ;*************************************************************************
- ; Specify TSR's signature words:
- TSRsigA equ 'TS' ;'TSRBONES' Signature
- TSRsigB equ 'RB'
- TSRsigC equ 'ON'
- TSRsigD equ 'ES'
- ;*************************************************************************
- Entry ENDP ;v0.01
- ;
- ;*************************************************************************
- SUBTTL User-supplied TSR Routine
- PAGE
- ;*************************************************************************
- ROUTINE PROC NEAR
- ;*************************************************************************
- ; Code for your HotKey-triggered TSR routine GOES HERE:
- ; ( Here, a dummy routine has been placed which simply rings the
- ; terminal Bell whenever the TSR is triggered. )
- ;
- ; Announce this dummy TSR's trigger by a Bell signal:
- ;
- Enter:
- mov al,07h ;al = ASCII Bell.
- mov bh,0 ;Video page.
- mov cx,1 ;No. of bytes to write.
- mov ah,0Eh ;BIOS Int10,OEh=TTY Screen.
- Int 10h ;Write ASCII Bell to screen.
- ;
- Exit:
- ret ;Return from TSR routine.
- ;
- ROUTINE endp
- ;
- ; End of your HotKeyed TSR routine.
- ;***************************************************************************
- SUBTTL Hooked Interrupts
- PAGE
- ;***************************************************************************
- ;
- NewInt09 PROC FAR ;v0.01
- ;
- ; The following three instructions often are said to "simulate an interrupt"
- ; that calls the PRIOR interrupt handler routine and then the prior interrupt
- ; handler's IRET instruction pops the flags and returns here to the point
- ; after the following CALL instruction.
- ; The reason for "simulating the interrupt" here is to give prior (and
- ; presumably more time-critical) handlers a shot at processing this interrupt
- ; before we process with this TSR's code.
- ;
- pushf ;Push flags as a true interrupt would.
- cli ;Be sure interrupts are disabled.
- call CS:oldint09 ;Call FAR PTR address of old interrupt
- ; ; handler routine.
- ;
- ;
- push ax ;Prepare to check for Hotkey.
- push bx ;Save all registers (DS is already pushed).
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
- ;
- push CS ;Set up data segment
- pop DS ;register to point to code segment.
- ;
- ASSUME DS:CodeSeg ;v0.01
- ;
- ; Determine if the current Keyboard Interrupt (Int09h) occurred
- ; because this TSR's HotKey was pressed:
- in al,60h ;Get current Key Scan Code.
- cmp al,HOTKEY ;Is it HotKey's Scan Code?
- jne Exit09 ;Exit if not.
- mov ah,02h ;Int16h,Fcn02h:GetKEYFLAGBYTE.
- Int 16h ;Return Key Flag Byte in al.
- and al,LockKeyMask ;Mask out Num, Caps, Scroll Lock bits.
- cmp al,KEYFLAGBYTE ;Are the HotKey Flags active ?
- jne Exit09 ;Exit if not.
- ;
- ; At this point, Hotkey is known to have been pressed. First, purge
- ; the DOS Keyboard type-ahead buffer of the hot key(s) so they won't
- ; be passed on to DOS:
- ;
- ClrKbdBuf: ;Clear Keyboard buffer:
- mov ah,01h ;Get Keyboard buffer status
- int 16h ;via BIOS Interrupt 16h.
- jz BufClr ;Jump if buffer empty.
- mov ah,00h ;Get key from buffer (to purge it)
- int 16h ;via BIOS Interrupt 16h.
- jmp ClrKbdBuf ;Loop back to purge another key.
- BufClr:
- ;
- ; We shall allow other interrupts to occur during our TSR ROUTINE.
- ; If we didn't allow other interrupts (through the STI instruction),
- ; we could lock out time-critical interrupts from access to the CPU during
- ; our TSR routine. However, by allowing interrupts during our routine, we
- ; have an increased responsibility to make sure critical portions of our
- ; own code is not re-entered. (The "bellgate" stuff below is an example
- ; of a measure necessary to keep us from re-entering our own TSR's code).
- ; What we really want to do by allowing interrupts is to make the CPU avail-
- ; able to OTHER critical interrupt service routines WITHOUT swarming all over
- ; ourselves through multiple detections of our own HotKey.
- ; This "gate" technique is a good one to keep in
- ; mind whenever you have a code region in an interrupt handler
- ; that needs to be protected from re-entry:
- ;
- cmp bellgate,0 ;Is it clear to re-enter Hotkey code?
- jne BusyExit09 ;Exit if not,
- mov bellgate,1 ;Else, close gate and proceed.
- ;
- CLI ;DISABLE INTERRUPTS
- ; Now we will check to be sure that no time-critical hardware interrupt
- ; handling is underway. We do this by querying the Intel 8259A Program-
- ; mable Interrupt Controller (PIC) chip's In Service Register (ISR) and
- ; testing it to see that it is zero (i.e., nothing being serviced).
- ;
- HotKeyPressed:
- mov al,ISRREQ ;al=PIC's OCW3 to ask for ISR Register.
- out PICPORT,al ;Tell PIC to get ISR ready for reading.
- jmp Dally ;Give PIC time to make ISR available.
- Dally: in al,PICPORT ;Fetch the ISR Register from PIC.
- or al,al ;Activate processor flags.
- jnz SetFlag ;If al not zero, go set flag.
- ;
- ; At this point, HotKey is known to be pressed AND NO hardware interrupt
- ; is being serviced. BUT is InDOS flag zero, indicating that DOS is
- ; not busy and therefore can safely be entered? This will now be
- ; checked:
- ;
- HotKeyNoHWI:
- les bx,indosptr ;es:bx = pointer to InDOS flag
- mov al,es:[bx] ;al = InDOS flag.
- or al,al ;Activate processor flags.
- jnz SetFlag ;Jump if InDOS not zero.
- ;
- ; Include a check on Critical Error flag. Don't trigger the TSR if
- ; DOS is in the middle of handling a Critical Error:
- ;
- les bx,criterrptr ;es:bx = pointer to CritErr flag.
- mov al,es:[bx] ;al = CritErr flag.
- ;
- ; Also, don't trigger the TSR if time-critical Disk access is underway:
- ; Normally, this Disk check would not be necessary since the
- ; InDOS flag would not be clear during Disk accesses, BUT some
- ; software will bypass DOS and go directly to the BIOS Int13
- ; Interrupt for Disk access. Therefore, to be safe, we HAVE to
- ; be sure Int13 has not been entered and is not in the process
- ; of performing time-critical Disk stuff when we hit the TSR
- ; HotKey. Many TSRs don't even check this. They just depend
- ; upon users not to hit the HotKey during Disk access. That seems
- ; terribly risky to me:
- ;
- or al,diskflag ;al = CritErr | diskflag
- ; (| => Logical OR).
- jnz Exit09 ;If al not zero, try again later.
- ;
- ; Also, don't trigger the TSR if a PrtScrn is in progress:
- ; (Is this really necessary? I don't think TSR will trigger during PrtSc)
- les bx,prtscrn ;ES:bx = pointer to PrtScrn busy flag.
- cmp BYTE PTR es:[bx],1 ;Is PrtScrn in progress?
- je Exit09 ;If so, try again later.
- ;
- STI ;Allow other interrupts in our TSR.
- ;
- call ROUTINE ;All is clear!, so call routine.
- mov hotkeyflag,0 ;Be sure HotKey flag is reset.
- jmp SHORT Exit09 ;Exit after TSR routine.
- ;
- SetFlag:
- mov hotkeyflag,1 ;Set HotKey Flag for use by Int28h.
- ;
- Exit09:
- mov CS:bellgate,0 ;Open gate allowing new HotKey detect.
- BusyExit09:
- pop es ;Restore all registers
- pop ds
- ASSUME DS:NOTHING ;v0.01
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ;
- ;
- ; Return from this TSR's Keyboard Interrupt 09h handler routine:
- iret
- ;
- NewInt09 ENDP ;v0.01
- ;
- ;*************************************************************************
- PAGE
- ;*************************************************************************
- NewInt13 PROC FAR ;We hook Int13h only for purpose
- ;of setting a flag to prevent our
- ;TSR from triggering during time-
- ;critical Disk accesses.
- mov CS:diskflag,1 ;Set flag to show Disk access.
- ;
- pushf ;Invoke prior Int13 handler
- cli ;(be sure interrupts disabled)
- call CS:oldint13 ;by simulating an interrupt.
- ;
- mov CS:diskflag,0 ;Clear flag to show Disk finished.
- ;
- ; The following RET 2 bumps the SP register up by 2 bytes to effectively
- ; take the flags off the stack (where they were put by the invoking
- ; INT 13h) WITHOUT popping them off and ruining the meaningful flags
- ; left in the Flags register by the original DOS INT13 handler (the
- ; DOS INT13 handler also returns via a RET 2 to keep from ruining the
- ; Flags that the handler has painstakingly prepared for communicating
- ; back to the calling program). The effect on the stack pointer, SP, is
- ; exactly the same as with the more usual IRET. It is just that the Flags
- ; in the Flag register are preserved at the values the handler placed
- ; and wanted there.
- ;
- RET 2 ;Return from interrupt while
- ;preserving flags.
- ;
- NewInt13 ENDP
- ;*************************************************************************
- PAGE
- ;*************************************************************************
- NewInt16 PROC FAR ;v0.01
- ;
- push ds ;Entry for New Int. Handler.
- ; ;Save required registers.
- ;
- push CS ;Set data seg v0.01
- pop DS ;to our CodeSeg v0.01
- ASSUME DS:CodeSeg ;v0.01
- ;
- ; This next portion of code provides back to the non-resident
- ; TSR installation code a check on whether the TSR has already been installed.
- ; It does this through the following technique:
- ; Check to see if the ax, bx, cx, dx registers are loaded with this
- ; TSR's signature words. Since all TSR ax signature words are chosen
- ; so as NOT to match any allowed DOS Int16h Function in ah, ALL
- ; standard DOS Int16h calls will exit from this sequence of compares
- ; at the first JNE instruction below and will ultimately be processed
- ; by the standard DOS Int16h handler.
- ; The ONLY place where all the registers are loaded with THIS TSR's
- ; signature words and then Int16h called is IN THE INITIALIZATION CODE
- ; AT THE END OF THIS TSR. Given that all the signature words are matched
- ; in the four comparisons below, we need to signal back to the
- ; invoking TSR initialization code by setting the data registers to
- ; values that NEVER would be returned by the standard DOS Int16h handler,
- ; and that therefore could ONLY have come from this previously-installed
- ; TSR's Int16h handler code. The TSR installation code will then take
- ; the return of these unique register values as the indication that
- ; this TSR has already been installed.
- ;
- cmp ax,TSRsigA ;Is ax = TSR signature word A?
- jne Exit16 ;No, let regular Int16 handle this.
- cmp bx,TSRsigB ;Is bx = TSR signature word B?
- jne Exit16 ;No, let regular Int16 handle this.
- cmp cx,TSRsigC ;Is cx = TSR signature word C?
- jne Exit16 ;No, let regular Int16 handle this.
- cmp dx,TSRsigD ;Is dx = TSR signature word D?
- jne Exit16 ;No, let regular Int16 handle this.
- ;
- ; The ONLY way you ever get to here is by having called Int16h with the
- ; ax, bx, cx, dx registers loaded with this TSR's signature words. This
- ; only occurs in the TSR initialization routine. Therefore, set the
- ; registers to return values that a DOS Int16h never would, and then
- ; return from this interrupt back to the TSR initialization routine.
- ;
- xchg bx,cx ;Exchange regs. (DOS Int16h wouldn't do this)
- xchg ax,dx ; " " "
- ;
- pop ds ;Restore regs.
- iret ;Return from Int to TSR Initialize routine.
- ;
- Exit16:
- pop ds ;Restore all registers
- ASSUME DS:NOTHING ;v0.01
- ;
- ; Chain to prior Interrupt 16h handler routine:
- jmp CS:oldint16
- ;
- NewInt16 ENDP ;v0.01
-
- ;*************************************************************************
- PAGE
- ;*************************************************************************
- NewInt28 PROC FAR ;v0.01
- ;
- pushf ;Call prior handler.
- cli
- call CS:oldint28
- ;
- ; Determine if this TSR's HotKey has been flagged as pressed:
- cmp CS:hotkeyflag,1 ;Has HotKey been pressed?
- jne QuickExit ;Exit if not.
- ;
- cmp CS:bellgate,1 ;Is gate closed?
- je QuickExit ;If so, exit.
- mov CS:bellgate,1 ;Else close gate and proceed.
- ;
- CLI ;DISABLE INTERRUPTS
- ; If you are here, then HotKey has been pressed.
- push ax ;Entry for New Int. Handler.
- push bx ;Save all registers.
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
- ;
- push CS
- pop DS
- ASSUME DS:CodeSeg ;v0.01
- ;
- ;
- ; Make sure InDOS flag is no greater than 1. The InDOS flag equals
- ; the number of DOS calls currently active. If we want to be sure
- ; that we do not disrupt DOS by reentry in our TSR user routine,
- ; we have to be sure that the present Int28 has occurred while
- ; only 1-deep into DOS calls (as it is when DOS is TRULY idling):
- les bx,indosptr ;ES:bx points to InDOS flag.
- cmp BYTE PTR ES:[bx],1 ;Is InDOS flag above 1?
- ja Exit28 ;Exit if InDOS > 1.
- ;
- ; DOS is known to be idling at this point.
- ; At this point, HotKey is known to have been pressed. Now we will
- ; check to be sure that no time-critical hardware interrupt handling
- ; is underway. We do this by querying the Intel 8259A Programmable
- ; Interrupt Controller (PIC) chip's In Service Register (ISR) and
- ; testing it to see that it is zero (i.e., nothing being serviced
- ; except Int09 (PIC's IRQ1) ):
- HotKeyPressed2:
- mov al,ISRREQ ;al=PIC's OCW3 to ask for ISR Register.
- out PICPORT,al ;Tell PIC to get ISR ready for reading.
- jmp Dally2 ;Give PIC time to make ISR available.
- Dally2: in al,PICPORT ;Fetch the ISR Register from PIC.
- ;
- ; Also, don't trigger the TSR if time-critical Disk access is underway:
- or al,diskflag ;al = ISR | diskflag. (| => Logical OR).
- jnz Exit28 ;If al not zero, try again later.
- ;
- ; Also, don't trigger the TSR if a PrtScrn is in progress:
- ; (Is this really necessary? I don't think TSR will trigger during PrtSc)
- les bx,prtscrn ;ES:bx = pointer to PrtScrn busy flag.
- cmp BYTE PTR es:[bx],1 ;Is PrtScrn in progress?
- je Exit28 ;If so, Exit w/o triggering TSR.
- ;
- STI ;ENABLE OTHER INTERRUPTS.
- ;
- HotKeyFlagSet:
- ; Here, HotKey is flagged as pressed and DOS is idling (since we are
- ; servicing Int28h) and no hardware interrupts are being handled.
- ; Also, no Print Screen or Disk access is underway.
- ; DOS Int21h Functions above 0Ch can be accessed if required in your
- ; TSR routine:
- ;
- call ROUTINE ;Call TSR routine; DOSOK & No Hardware
- ;interrupts being serviced.
- mov CS:hotkeyflag,0 ;Clear HotKey Flag.
- ;
- Exit28:
- pop es ;Restore all registers
- pop ds
- ASSUME ds:NOTHING
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- mov CS:bellgate,0
- ;
- QuickExit:
- ; Return from this Keyboard Interrupt 28h handler routine:
- iret
- ;
- NewInt28 ENDP ;v0.01
- ;*************************************************************************
- ; -END OF TSR's RESIDENT CODE-
- ; Only the code above will remain locked in memory
- ; after the initialization performed below.
- ;*************************************************************************
- SUBTTL TSR BOOSTER (Initialization)
- PAGE
- ;*************************************************************************
- ; BEGINNING OF TSR's INITIALIZATION CODE (THE "BOOSTER"):
- ; The following code is protected in RAM *ONLY* during initialization
- ; of the TSR that occurs when the TSR name is first invoked
- ; at the DOS command level. All the following code is abandonned
- ; unprotected in RAM after the Terminate-and-Stay-Resident (TSR)
- ; call to Function 31h of DOS Interrupt 21h below. This
- ; is allowed to happen because the code's work is complete at
- ; that point. The code will be overwritten as the memory which
- ; it temporarily occupied is needed by DOS for other purposes.
- ;
- ; I have seen this following section of code colorfully called
- ; the TSR "Booster". This is quite appropriate since the code
- ; sits here, strapped to the very end of the TSR, and it is of
- ; use only during the "blastoff" (initialization) of the TSR, when
- ; it is used to put the TSR into "orbit" (residency), and after
- ; which it is "jettisoned" (abandonned unprotected in memory) by
- ; the DOS TSR call, Int 21h, Fcn 31h.
- ;
- TSRinit PROC NEAR ;v0.01
- EndDump EQU $ ;Roy Silvernail - Keep TASM 1.0 happy
- ;when computing # resident paragraphs.
- ;
- ; Get DOS Version Number:
- mov ah,30h ;Fcn 30h = Get DOS Version
- int 21h ;DOS Version = al.ah
- ;
- ; If this is DOS v.1.x, this TSR cannot work, so go print message
- ; and exit without installing:
- cmp al,1 ;Is this DOS Version 1.x?
- ja DOSverOK ;If not, DOS version is OK.
- push bx ;A "push" for the "pop" at DOSver1 label.
- jmp DOSver1 ;If so, TSR won't work so exit.
- ;
- DOSverOK:
- ; If here, DOS version is 2.0 or later. TSR can work, so proceed.
- ;
- ; Check for prior installation of this TSR:
- ;
- mov ax,TSRsigA ;Prime registers for our
- mov bx,TSRsigB ;Int16h handler's check
- mov cx,TSRsigC ;for prior installation
- mov dx,TSRsigD ;thru TSR signature words.
- ;
- Int 16h ;Check prior installation.
- ;
- cmp ax,TSRsigD ;Was TSR signature detected?
- jne Install ;If not, Install it.
- cmp bx,TSRsigC
- jne Install
- cmp cx,TSRsigB
- jne Install
- cmp dx,TSRsigA
- jne Install
- ;
- ; If you are here, all four TSR signature words were detected and signalled,
- ; so the TSR is already installed.
- ; Announce the TSR's PRIOR Installation and exit:
- mov dx,Offset PriorInstMsg ;DX points to message.
- mov ah,09h ;DOS Fcn. 09h=Display String.
- Int 21h ;Display String via DOS.
- ;
- mov ax,4C00h ;Fcn 4C = DOS Terminate call
- Int 21h ;Do it.
- ;
- Install:
- ; If you are here, then DOS version is 2.+ and the TSR has not
- ; previously been installed.
- ;
- ; To conserve RAM usage, release from memory the copy of the DOS
- ; Environment passed to this TSR (this assumes, of course, that
- ; your Interrupt handler routine will not need to reference this
- ; de-allocated Environment) So, if you are going to write your
- ; TSR routine to reference the Environment, DON'T DEALLOCATE IT
- ; HERE.
- ;
- ;Get segment of Environment
- ;from 02Ch in the Program
- ;Segment Prefix (PSP).
- ;
- mov ES,envseg ;ES=PSP's environ seg v0.01
- mov ah,49h ;DOS Fcn 49h = Release Memory
- int 21h ;Release it via DOS interrupt.
- ;
- ; In order to make the TSR's command name show under the "owner" column in
- ; the "MAPMEM" command of Kim Kokkonen's excellent TSR Mark/Release
- ; package, allocate a tiny 1-paragraph "Pseudo-Environment" here which
- ; contains nothing but the TSR name.
- ;
- ; Allocate the memory needed by the tiny 'Pseudo-Environment":
- mov bx,1 ;Allocate one parag. (16bytes)
- mov ah,48h ;and return allocation
- int 21h ;segment in ax via DOS call.
- ;
- mov ES,ax ;Pseudo-Env. Segment to ES.
- mov si,OFFSET PseudoEnv ;si=source string OFFSET.
- mov di,0 ;di=destination string OFFSET.
- mov cx,ENVLNGTH ;cx=Bytes in Pseudo-Env.string.
- cld ;Forward string move direction.
- rep movsb ;Move Pseudo-Env. string @ DS:si to ES:di
- ;
- ; Set PSP's Environment segment pointer to point to tiny Pseudo-Environment.
- mov envseg,ES
- ;
- ;*****************************************************************************
- ; NOW, capture all the required Interrupts:
- ;
- ; **** INT 09 ****
- ; Get Old Interrupt 09h Vector:
- mov ax,3500H+HOOK09 ;Get old Int 9 vector v0.01
- int 21h ;Int.Vector in ES:BX via DOS.
- ;
- ; Save Old Interrupt 09h Vector:
- mov Word Ptr oldint09,bx ;Save Offset of Old Interrupt.
- mov word ptr oldint09+2,ES ;save seg v0.01
- ;
- ; Install New Interrupt Vector to this TSR's "NewInt09:" Label:
- mov ax,2500H+HOOK09 ;Set new Int 9 vector v0.01
- mov dx,Offset NewInt09 ;dx=Offset of New Int Handler.
- int 21h ;Set New Int via DOS.
- ;
- ; **** INT 13 ****
- ; Get Old Interrupt 13h Vector:
- mov ax,3500H+HOOK13 ;Get old Int 13 vector
- int 21h ;Int.Vector in ES:BX via DOS.
- ;
- ; Save Old Interrupt 13h Vector:
- mov Word Ptr oldint13,bx ;Save Offset of Old Interrupt.
- mov word ptr oldint13+2,ES ;save Segment.
- ;
- ; Install New Interrupt Vector to this TSR's "NewInt13:" Label:
- mov ax,2500H+HOOK13 ;Set new Int 13 vector.
- mov dx,Offset NewInt13 ;dx=Offset of New Int Handler.
- int 21h ;Set New Int via DOS.
- ;
- ; **** INT 16 ****
- ; Get Old Interrupt 16h Vector:
- mov ax,3500H+HOOK16 ;get old Int 16H vector v0.01
- int 21h ;Int.Vector in ES:BX via DOS.
- ;
- ; Save Old Interrupt 16h Vector:
- mov Word Ptr oldint16,bx ;Save Offset of Old Interrupt.
- mov word ptr oldint16+2,ES ;save segment v0.01
- ;
- ; Install New Interrupt Vector to this TSR's "NewInt16:" Label:
- mov ax,2500H+HOOK16 ;set new Int 16H vector v0.01
- mov dx,Offset NewInt16 ;dx=Offset of New Int Handler.
- int 21h ;Set New Int via DOS.
- ;
- ; **** INT 28 ****
- ; Get Old Interrupt 28h Vector:
- mov ax,3500H+HOOK28 ;Get old Int 28H vector v0.01
- int 21h ;Int.Vector in ES:BX via DOS.
- ;
- ; Save Old Interrupt 28h Vector:
- mov Word Ptr oldint28,bx ;Save Offset of Old Interrupt.
- mov word ptr oldint28+2,ES ;save segment v0.01
- ;
- ; Install New Interrupt Vector to this TSR's "NewInt28:" Label:
- mov ax,2500H+HOOK28 ;set new Int 28H vector v0.01
- mov dx,Offset NewInt28 ;dx=Offset of New Int Handler.
- int 21h ;Set New Int via DOS.
- ;
- ;*****************************************************************************
- ; Get Pointer to InDOS flag ("DOS Busy" flag) and save it:
- mov ah,34h ;DOS FCN=34h:Get InDOS Pointer.
- int 21h ;Pointer in ES:BX
- mov Word Ptr indosptr,bx ;Save Offset of InDOS flag.
- mov Word Ptr indosptr+2,ES ;Save Segment of InDOS flag.
- ;
- mov Word Ptr criterrptr+2,ES ;Also, Seg of CritErr flag.
- push bx ;Save indosptr on stack for use below.
- ;
- ; Get DOS Version Number:
- mov ah,30h ;Fcn 30h = Get DOS Version
- int 21h ;DOS Version = al.ah
- ;
- ; If DOS version is 2.x, then DOS Critical Error flag is @ indosptr + 1.
- ; If DOS version is 3.x+, then DOS Critical Error flag is @ indosptr - 1.
- ; Determine DOS Version:
- cmp al,2 ;Is it DOS Version 2.x?
- je DOSver2 ;If yes, jump;
- ja DOSver3 ;or, if later version, jump;
- ;else, it's DOS Version 1.x:
- ;
- DOSver1: ;If here, DOS Version 1.x is being run:
- mov dx,OFFSET BailOutMsg ;TBONES needs DOS 2.x or later.
- mov ah,09h ;Say we're sorry, but NO GO
- int 21h ;via DOS.
- pop bx ;Clear stack.
- int 20h ;Terminate without installing
- ;in only way DOS 1.x knows.
- ;
- DOSver2: ;If here, DOS Version 2.x is being run:
- pop bx ;Get indosptr from stack.
- inc bx ;CritErr flag is @ indosptr+1.
- mov Word Ptr criterrptr,bx ;Save CritErr Pointer.
- jmp Announce ;Go announce TSR installed.
- ;
- DOSver3: ;If here, DOS Version 3.+ is being run:
- pop bx ;Get indosptr from stack.
- dec bx ;CritErr flag is @ indosptr-1.
- mov Word Ptr criterrptr,bx ;Save CritErr Pointer.
- ;
- ; Announce the TSR's Installation:
- Announce:
- mov dx,Offset InstallMsg ;DX points to message.
- mov ah,09h ;DOS Fcn. 09h=Display String.
- int 21h ;Display String via DOS.
- ;
- ; Lock resident code in memory via Terminate-and-Stay-Resident (TSR) DOS call:
- ;
- ;v0.11 DX requires size of resident code (in 16-byte paragraphs)
- ; This awkward construct is required to keep
- ; DOS Function 31h happy. Notice how we first compute
- ; the length of the TSR code in bytes [i.e., end of
- ; the TSR code (EndDump) minus start of the TSR code
- ; (0, our BeginDump)], round it up to the next whole paragraph ( + 0Fh),
- ; and then divide by 16 (SHR 4) to get the number of resident paragraphs:
- ;
- mov dx,(EndDump-BeginDump+0Fh)/16
- ;Roy Silvernail discovered that the BeginDump and EndDump symbols
- ;were necessary to keep TASM 1.0 happy when computing # resident paragraphs
- ;in the above statement.
- ;
- mov ah,31h ;DOS FCN 31h=TSR Call.
- int 21h ;Go Resident via DOS TSR call.
- ;
- PseudoEnv: DB ' ',0,0,1,0,'TSRBONES',0
- ENVLNGTH EQU $-PseudoEnv
- ;
- BailOutMsg:
- db 0Dh,0Ah
- db 'Sorry. TSRBONES needs DOS v.2+. You have v.1.x'
- db 0Dh,0Ah,'$'
- PriorInstMsg:
- db 0Dh,0Ah
- db 'TSRBONES IS *ALREADY* INSTALLED.'
- InstallMsg:
- db 0Dh,0Ah
- db 'HotKey => Ctrl-Alt-B'
- db 0Dh,0Ah
- db 0Dh,0Ah
- db 'TSRBONES Version 0.1'
- db 0Dh,0Ah
- db 'Copyright (C) 1990 by Robert Curtis Davis'
- db 0Dh,0Ah,'$'
- ;
- TSRinit ENDP ;v0.01
-
- CodeSeg ends
- end Entry
- ;***********************************************************************
-